package com.cdel.akka.AkkainJAVA.demo1;

import java.util.concurrent.TimeUnit;

import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Inbox;
import akka.actor.Props;

/**首先是定义的几个消息.在Akka中传递的消息必须实现Serializable接口.WhoToGreet消息表示了打招呼的人,Greeting表示了招呼的内容,而Greet表示了打招呼这个动作.

接着就是两个最重要的Actor了.GreetPrinter非常简单,接收到消息后,判断消息的类型,如果是Greeting招呼内容,那么就直接打印消息到控制台.而Greeter这个Actor稍微复杂点,它消费两种不同的消息,如果是WhoToGreet,那么就把要打招呼的人记录到自己的上下文中,如果是Greet,那么就构造出招呼的内容,并把消息反馈回sender.

最后,再来分析下DemoMain.

一来,先创建了一个ActorSystem,
然后创建了一个GreeterActor的实例,命名为greeter.
接着,为这个Actor,显示的创建了一个邮箱.
而后,调用greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());,表示给greeter这个Actor发送一个消息,消息的内容是WhoToGreet,发送者是空.这就意味着在greeter这个Actor内部,调用sender是不能获取到发送者的.通过这个动作,就把消息限定为了单向的.
再然后,通过inbox.send(greeter, new Greet());,使用邮箱显示的发送一个Greet消息给greeter.这是给Actor发送消息的另外一种方法,这种方法通常会有更高的自主性,能完成更多更复杂的操作.但是调用起来比直接使用ActorRef来的复杂.
Greeting greeting1 = (Greeting) inbox.receive(Duration.create(5, TimeUnit.SECONDS));表示的就是尝试在5秒钟内,从Inbox邮箱中获取到反馈消息.如果5秒内没有获取到,那么就抛出TimeoutException异常. 由于我们在greeter这个Actor中有处理,接收到Greet消息后,就构造一个Greeting消息给sender,因此这个地方是能够正确的获取到消息的反馈的.
后面的操作都是一样的,就不再重复描述.
只有最后一个代码稍微有点不一样system.scheduler().schedule(Duration.Zero(), Duration.create(1, TimeUnit.SECONDS), greeter, new Greet(), system.dispatcher(), greetPrinter);,这个使用了ActorSystem中的调度功能.每一秒钟给greeter这个Actor发送一个Greet消息,并指定消息的发送者是greetPrinter.这样每隔一秒钟,greeter就会收到Greet消息,然后构造成Greeting消息,又返回给GreetPrinter这个Actor,这个Actor接收到消息后,打印出来.形成一个环流.
 * @author DELL
 *
 */
public class DemoMain {
    public static void main(String[] args) throws Exception {
        final ActorSystem system = ActorSystem.create("helloakka");
        // 创建一个到greeter Actor的管道
        final ActorRef greeter = system.actorOf(Props.create(GreeterActor.class), "greeter");
        // 创建邮箱
        final Inbox inbox = Inbox.create(system);
        // 先发第一个消息,消息类型为WhoToGreet
        greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());
        // 真正的发送消息,消息体为Greet
        inbox.send(greeter, new Greet());
        // 等待5秒尝试接收Greeter返回的消息
        Greeting greeting1 = (Greeting) inbox.receive(Duration.create(5, TimeUnit.SECONDS));
        System.out.println("Greeting: " + greeting1.message);
        // 发送第三个消息,修改名字
        greeter.tell(new WhoToGreet("typesafe"), ActorRef.noSender());
        // 发送第四个消息
        inbox.send(greeter, new Greet());

        // 等待5秒尝试接收Greeter返回的消息
        Greeting greeting2 = (Greeting) inbox.receive(Duration.create(5, TimeUnit.SECONDS));
        System.out.println("Greeting: " + greeting2.message);
        // 新创建一个Actor的管道
        ActorRef greetPrinter = system.actorOf(Props.create(GreetPrinterActor.class));

        //使用schedule 每一秒发送一个Greet消息给 greeterActor,然后把greeterActor的消息返回给greetPrinterActor
        system.scheduler().schedule(Duration.Zero(), Duration.create(1, TimeUnit.SECONDS), greeter, new Greet(), system.dispatcher(), greetPrinter);
        //system.shutdown();
    }
}